package com.haidao.admin.component.service.impl;

import com.haidao.admin.component.dao.TaskDao;
import com.haidao.admin.component.entity.Task;
import com.haidao.admin.component.params.TaskParam;
import com.haidao.admin.component.params.TaskUpdateParam;
import com.haidao.admin.component.service.TaskService;
import com.haidao.admin.component.web.job.ReportJob;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author lyy
 * @Date 2023/11/10
 */
@Slf4j
@Service
public class TaskServiceImpl implements TaskService {

    public TaskServiceImpl() throws SchedulerException {
        this.scheduler = StdSchedulerFactory.getDefaultScheduler();
    }

    public static final String DEFAULT_JOB_GROUP_NAME = "job_group";

    public static final String DEFAULT_TRIGGER_GROUP_NAME = "trigger_group";

    private Scheduler scheduler;

    private TaskDao taskDao;

    @Resource
    public void setTaskDao(TaskDao taskDao) {
        this.taskDao = taskDao;
    }

    @Override
    public Page<Task> list(TaskParam param) {
        Task task = new Task();
        task.setName(param.getName());
        task.setState(param.getState());

        ExampleMatcher matcher = ExampleMatcher.matching() //构建对象
                .withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING) //改变默认字符串匹配方式：模糊查询
                .withIgnoreCase(true);

        Example<Task> ex = Example.of(task, matcher);
        int page= param.getPage()>0?param.getPage()-1:0;
        PageRequest request = PageRequest.of(page, param.getPageSize());
        return taskDao.findAll(ex, request);
    }

    @Override
    public List<Task> getAll() {
        return taskDao.findAll();
    }

    @Override
    public void create(Task task) {
        taskDao.save(task);
        task.setCron(genCron(task.getRate(), task.getCycle()));
        Map<String, Object> params = new HashMap<>();
        params.put("code", task.getTaskKey());
        params.put("taskId", task.getId());
        this.addJob(String.valueOf(task.getId()), task.getCron(), params, ReportJob.class);
    }

    @Override
    public void update(Task task) {
        task.setCron(genCron(task.getRate(), task.getCycle()));
        taskDao.save(task);
        this.removeJob(String.valueOf(task.getId()));
        if (task.getState() == 1) {
            Map<String, Object> params = new HashMap<>();
            params.put("code", task.getTaskKey());
            params.put("taskId", task.getId());
            this.addJob(String.valueOf(task.getId()), task.getCron(), params, ReportJob.class);
        }
    }

    @Override
    public void batchUpdate(TaskUpdateParam task) {
        for (Long id : task.getIds()) {
            Task t = detail(id);
            if (t != null) {
                if (task.getState() != null) {
                    t.setState(task.getState());
                }
                if (task.getCycle() != null) {
                    t.setCycle(task.getCycle());
                }
                if (task.getRate() != null) {
                    t.setRate(task.getRate());
                }
                t.setCron(genCron(t.getRate(), t.getCycle()));
                taskDao.save(t);
                this.removeJob(String.valueOf(t.getId()));
                if (t.getState() == 1) {
                    Map<String, Object> params = new HashMap<>();
                    params.put("code", t.getTaskKey());
                    params.put("taskId", t.getId());
                    this.addJob(String.valueOf(t.getId()), t.getCron(), params, ReportJob.class);
                }
            }
        }
    }

    @Override
    public Task detail(Long taskId) {
        return taskDao.findById(taskId).get();
    }


    @Override
    public void addJob(String jobName, String cronExpression, Map<String, Object> params, Class<? extends Job> jobClass) {
        try {
            JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, DEFAULT_JOB_GROUP_NAME).build();
            jobDetail.getJobDataMap().putAll(params); // 添加参数

            // 表达式调度构建器
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
            Trigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, DEFAULT_TRIGGER_GROUP_NAME).withSchedule(cronScheduleBuilder).build();

            // 交给scheduler去调度
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            scheduler.scheduleJob(jobDetail, trigger);

            if (!scheduler.isShutdown()) { // 启动
                log.info("启动任务[{}]", jobName);
                scheduler.start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void removeJob(String jobName) {
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, DEFAULT_TRIGGER_GROUP_NAME);
        JobKey jobKey = JobKey.jobKey(jobName, DEFAULT_JOB_GROUP_NAME);
        try {
            Scheduler scheduler = this.scheduler;
            Trigger trigger = scheduler.getTrigger(triggerKey);
            if (trigger == null) {
                return;
            }
            scheduler.pauseTrigger(triggerKey); // 停止触发器
            scheduler.unscheduleJob(triggerKey); // 移除触发器
            scheduler.deleteJob(jobKey); // 删除任务
            log.info("移除任务[{}]", jobName);
        } catch (Exception e) {
            //throw new ServiceException(e);
        }
    }

    @Override
    public void startNow(String jobName,Map<String, Object> params, Class<? extends Job> jobClass) throws Exception {
        jobName+="_now";
        removeJob(jobName);
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(jobName, DEFAULT_TRIGGER_GROUP_NAME)
                .startNow()
                .build();

        JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, DEFAULT_JOB_GROUP_NAME).build();
        jobDetail.getJobDataMap().putAll(params);

        // 交给scheduler去调度
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        scheduler.scheduleJob(jobDetail, trigger);

        if (!scheduler.isShutdown()) { // 启动
            log.info("启动任务[{}]", jobName);
            scheduler.start();
        }
    }

    public String genCron(int rate, int cycle) {
        String[] cronArr = new String[]{"*", "*", "*", "*", "*", "?"};
        if (rate > 0 && rate < 6) {
            cronArr[rate - 1] = cronArr[rate - 1] + "/" + cycle;
        }
        return StringUtils.join(cronArr, " ");
    }

}
